#include "stdafx.h"
#include "CppUnitTest.h"

#include "ProcParamsDefs.h"
#include "ProcParamDef.h"
#include "ProcParamDefInt.h"
#include "ProcParamDefDouble.h"
#include "ProcParamDefString.h"

#include "ProcParam.h"
#include "ProcParamDouble.h"
#include "ProcParamInt.h"
#include "ProcParamString.h"
#include "ProcParams.h"
#include "ProcParamsOutputs.h"
#include "ProcParamsInputs.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace PluginICProcStepsTest
{
	TEST_CLASS(ProcParamTest)
	{
	private:
		ProcParamsInputs *_inputParams;
		ProcParamsOutputs *_outputParams;

	public:

		TEST_METHOD_INITIALIZE(InitProcParamTest)
		{
			_inputParams = new ProcParamsInputs();
			_inputParams->ClearParams();

			_outputParams = new ProcParamsOutputs();
			_outputParams->ClearParams();

		}

		TEST_METHOD_CLEANUP(DeinitProcParamTest)
		{
			if (_inputParams != '\0')
				delete _inputParams;
			if (_outputParams != '\0')
				delete _outputParams;
		}
		
		TEST_METHOD(CreateInputParamsOutputParamsTest)
		{
			Assert::IsNotNull (_outputParams);
			Assert::IsNotNull (_inputParams);

			Assert::AreEqual( ProcParams::NotFound,  _inputParams->GetParamCount());
			Assert::IsNull (_inputParams->GetParamByPosition(0));
			Assert::IsNull ( _inputParams->GetParamByPosition(1));
			Assert::IsNull (_inputParams->GetParamByPosition(2));
			Assert::IsNull (_inputParams->GetParamByPosition(-1));
		}

		TEST_METHOD(ProcParmIntTest)
		{
			ProcParamInt *pInt = new ProcParamInt(0, "one", IPluginICProcStepsParam::input, 1);
			Assert::IsNotNull (pInt);
			Assert::IsTrue(  IPluginICProcStepsParam::input == pInt->GetDirection());
			Assert::IsTrue( pInt->IsValid());
			Assert::AreEqual(  1,  pInt->GetValue());
			Assert::IsTrue( IPluginICProcStepsParamDefIntP == pInt->GetType());
			pInt->SetValue(2);
			Assert::AreEqual(  2,  pInt->GetValue());

			delete pInt;

			pInt = new ProcParamInt(0, '\0', IPluginICProcStepsParam::output, 1);
			Assert::IsNotNull (pInt);
			Assert::IsTrue( IPluginICProcStepsParam::output == pInt->GetDirection());

			Assert::IsFalse(pInt->IsValid());
			Assert::AreEqual(  1,  pInt->GetValue());
			delete pInt;

			pInt = new ProcParamInt(-1, "one", IPluginICProcStepsParam::input, 1);
			Assert::IsNotNull (pInt);
			Assert::IsTrue( IPluginICProcStepsParam::input == pInt->GetDirection());

			Assert::IsFalse(pInt->IsValid());
			Assert::AreEqual( 1,  pInt->GetValue());
			delete pInt;
		}

		TEST_METHOD(ProcParmDoubleTest)
		{
			ProcParamDouble *pDouble = new ProcParamDouble(0, "one", IPluginICProcStepsParam::input, 1.0);
			Assert::IsTrue(IPluginICProcStepsParam::input == pDouble->GetDirection());
			Assert::IsNotNull (pDouble);
			Assert::IsTrue( pDouble->IsValid());
			Assert::AreEqual(  1.0,  pDouble->GetValue());
			Assert::IsTrue( pDouble->GetType() == IPluginICProcStepsParamDefDoubleP);
			pDouble->SetValue(2.1);
			Assert::AreEqual( 2.1,  pDouble->GetValue());
			delete pDouble;

			pDouble = new ProcParamDouble(0, '\0', IPluginICProcStepsParam::output,  1.0);
			Assert::IsTrue( IPluginICProcStepsParam::output == pDouble->GetDirection());
			Assert::IsNotNull (pDouble);
			Assert::IsFalse(pDouble->IsValid());
			Assert::AreEqual(  1.0,  pDouble->GetValue());
			delete pDouble;

			pDouble = new ProcParamDouble(-1, "one", IPluginICProcStepsParam::output, 1.0);
			Assert::IsNotNull (pDouble);
			Assert::IsFalse(pDouble->IsValid());
			Assert::AreEqual(  1.0,  pDouble->GetValue());
			delete pDouble;
		}

		TEST_METHOD(ProcParmStringTest)
		{
			ProcParamString *pString = new ProcParamString(0, "one", IPluginICProcStepsParam::output, "one");
			Assert::IsNotNull (pString);
			Assert::IsTrue(  pString->IsValid());
			Assert::AreEqual( "one",  pString->GetValue());
			Assert::IsTrue( pString->GetType() == IPluginICProcStepsParamDefStringP);
			pString->SetValue("two");
			Assert::AreEqual( "two",  pString->GetValue());
			delete pString;

			pString = new ProcParamString(-1, "one", IPluginICProcStepsParam::output, "one");
			Assert::IsNotNull (pString);
			Assert::IsFalse(pString->IsValid());
			Assert::AreEqual(  "one",  pString->GetValue());
			delete pString;

			pString = new ProcParamString(0, '\0', IPluginICProcStepsParam::output, "one");
			Assert::IsNotNull (pString);
			Assert::IsFalse(pString->IsValid());
			Assert::AreEqual( "one",  pString->GetValue());
			delete pString;

			pString = new ProcParamString(0, "one", IPluginICProcStepsParam::output, '\0');
			Assert::IsNotNull (pString);
			Assert::IsFalse(pString->IsValid());
			Assert::AreEqual(ProcParamString::BadValue,  pString->GetValue());
			delete pString;
		}

		TEST_METHOD(AddParamObjectTest)
		{
			Assert::AreEqual( ProcParams::NotFound,  _inputParams->GetParamCount());
			Assert::AreEqual( ProcParams::NotFound,  _outputParams->GetParamCount());

			Assert::IsFalse(_inputParams->AddParam('\0'));
			Assert::AreEqual(ProcParams::NotFound,  _inputParams->GetParamCount());

			Assert::IsTrue( _inputParams->AddParam(new ProcParamInt(0, "one", IPluginICProcStepsParam::input, 1)));
			Assert::IsTrue( _inputParams->Validate());
			Assert::AreEqual( 1,  _inputParams->GetParamCount());

			Assert::IsNull (_inputParams->GetParamByPosition(-1));
			Assert::IsNotNull (_inputParams->GetParamByPosition(0));
			Assert::IsNull (_inputParams->GetParamByPosition(1));

			Assert::IsFalse(_outputParams->AddParam('\0'));
			Assert::AreEqual( ProcParams::NotFound,  _outputParams->GetParamCount());
			Assert::IsTrue(_outputParams->AddParam(new ProcParamInt(0, IPluginICProcStepsParamAttribOutputNameResult, IPluginICProcStepsParam::output, 1)));
			Assert::IsTrue(_outputParams->Validate());
			Assert::AreEqual( 1,  _outputParams->GetParamCount());

			Assert::IsNull (_outputParams->GetParamByPosition(-1));
			Assert::IsNotNull (_outputParams->GetParamByPosition(0));
			Assert::IsNull (_outputParams->GetParamByPosition(1));

		}

		TEST_METHOD(AddParamObjectsTest)
		{
			Assert::AreEqual( ProcParams::NotFound,  _inputParams->GetParamCount());
			Assert::AreEqual( ProcParams::NotFound,  _outputParams->GetParamCount());

			Assert::IsTrue(_inputParams->AddParam(new ProcParamInt(0, "one", IPluginICProcStepsParam::input, 1)));
			Assert::IsTrue( _inputParams->Validate());
			Assert::AreEqual( 1,  _inputParams->GetParamCount());
			Assert::IsTrue( _inputParams->AddParam(new ProcParamInt(1, "two", IPluginICProcStepsParam::input, 1)));
			Assert::IsTrue(  _inputParams->Validate());
			Assert::AreEqual( 2,  _inputParams->GetParamCount());

			Assert::IsNotNull(_inputParams->GetParamByPosition(0));
			Assert::IsNotNull(_inputParams->GetParamByPosition(1));
			Assert::IsNull(_inputParams->GetParamByPosition(2));

			Assert::IsTrue( _inputParams->ClearParams());
			Assert::AreEqual( ProcParams::NotFound,  _inputParams->GetParamCount());

			Assert::IsFalse(_outputParams->ClearParams());		//returns false if no params to clear, but otherwise no problem
			Assert::AreEqual(ProcParams::NotFound,  _outputParams->GetParamCount());
		}

		TEST_METHOD(InputParamsGetObjectsTest)
		{
			std::string zero("zero");
			std::string one("one");
			std::string two("two");
			std::string three("three");
			std::string four("four");
		
			Assert::AreEqual(ProcParams::NotFound,  _inputParams->GetParamCount());

			Assert::IsFalse(_inputParams->AddParam(new ProcParamInt(0, '\0', IPluginICProcStepsParam::input,  1)));	//bad arg
			Assert::AreEqual(ProcParams::NotFound,  _inputParams->GetParamCount());

			Assert::IsTrue( _inputParams->AddParam(new ProcParamInt(0, zero.c_str(), IPluginICProcStepsParam::input, 0)));
			Assert::IsTrue( _inputParams->Validate());
			Assert::AreEqual( 1,  _inputParams->GetParamCount());

			Assert::IsTrue( _inputParams->AddParam(new ProcParamDouble(1, one.c_str(), IPluginICProcStepsParam::input, 1.0)));
			Assert::IsTrue( _inputParams->Validate());
			Assert::AreEqual( 2,  _inputParams->GetParamCount());

			Assert::IsTrue( _inputParams->AddParam(new ProcParamString(2, two.c_str(), IPluginICProcStepsParam::input, "two")));
			Assert::IsTrue( _inputParams->Validate());
			Assert::AreEqual( 3,  _inputParams->GetParamCount());

			Assert::IsFalse( _inputParams->AddParam(new ProcParamString(3, three.c_str(), IPluginICProcStepsParam::input, '\0')));	//bad arg
			Assert::AreEqual( 3,  _inputParams->GetParamCount());

			Assert::IsFalse( _inputParams->AddParam(new ProcParamInt(3, zero.c_str(), IPluginICProcStepsParam::input, 1)));	//duplicate name
			Assert::AreEqual( 3,  _inputParams->GetParamCount());
			Assert::IsFalse( _inputParams->AddParam(new ProcParamInt(2, three.c_str(), IPluginICProcStepsParam::input, 1)));	//duplicate index
			Assert::AreEqual( 3,  _inputParams->GetParamCount());

			Assert::IsTrue( _inputParams->AddParam(new ProcParamInt(4, four.c_str(), IPluginICProcStepsParam::input, 4)));
			Assert::AreEqual( ProcParams::NotFound,  _inputParams->GetParamCount());
			Assert::IsFalse( _inputParams->Validate());										//invalid as missing 3 index
			Assert::IsFalse( _inputParams->IsValid());

			Assert::IsTrue( _inputParams->AddParam(new ProcParamInt(3, three.c_str(), IPluginICProcStepsParam::input, 3)));
			Assert::IsTrue(  _inputParams->Validate());
			Assert::IsTrue( _inputParams->IsValid());
			Assert::AreEqual(5,  _inputParams->GetParamCount());

			Assert::AreEqual(zero.c_str(), _inputParams->GetParamByPosition(0)->GetName());
			Assert::AreEqual(one.c_str(), _inputParams->GetParamByPosition(1)->GetName());
			Assert::AreEqual(two.c_str(),  _inputParams->GetParamByPosition(2)->GetName());
			Assert::AreEqual(three.c_str(),   _inputParams->GetParamByPosition(4)->GetName());
			Assert::AreEqual(four.c_str(), _inputParams->GetParamByPosition(3)->GetName());

			Assert::AreEqual(zero.c_str(), _inputParams->GetParam(0)->GetName());
			Assert::AreEqual(one.c_str(),   _inputParams->GetParam(1)->GetName());
			Assert::AreEqual(two.c_str(),  _inputParams->GetParam(2)->GetName());
			Assert::AreEqual(three.c_str(),  _inputParams->GetParam(3)->GetName());
			Assert::AreEqual(four.c_str(),  _inputParams->GetParam(4)->GetName());

			Assert::IsNull(_inputParams->GetParam((const char *)'\0'));						//invalid param
			Assert::AreEqual(zero.c_str(), _inputParams->GetParam(zero.c_str())->GetName());
			Assert::AreEqual(one.c_str(), _inputParams->GetParam(one.c_str())->GetName());
			Assert::AreEqual(two.c_str(), _inputParams->GetParam(two.c_str())->GetName());
			Assert::AreEqual(three.c_str(), _inputParams->GetParam(three.c_str())->GetName());
			Assert::AreEqual(four.c_str(), _inputParams->GetParam(four.c_str())->GetName());

			Assert::AreEqual(0,  (dynamic_cast<ProcParamInt *>(_inputParams->GetParam(zero.c_str()))->GetValue()));
			Assert::AreEqual(1.0, (dynamic_cast<ProcParamDouble *>(_inputParams->GetParam(one.c_str()))->GetValue()));
			Assert::AreEqual(two.c_str(), (dynamic_cast<ProcParamString *>(_inputParams->GetParam(two.c_str()))->GetValue()));
			Assert::AreEqual(3, (dynamic_cast<ProcParamInt *>(_inputParams->GetParam(three.c_str()))->GetValue()));
			Assert::AreEqual(4, (dynamic_cast<ProcParamInt *>(_inputParams->GetParam(four.c_str()))->GetValue()));

			Assert::IsNull(dynamic_cast<ProcParamInt *>(_inputParams->GetParam(one.c_str())));	//wrong type, param is double, not int

			Assert::IsTrue(_inputParams->ClearParams());
			Assert::AreEqual( ProcParams::NotFound,  _inputParams->GetParamCount());
		}

		TEST_METHOD(InputParamsIsValidTest)
		{
			Assert::AreEqual( ProcParams::NotFound,  _inputParams->GetParamCount());
			Assert::IsFalse( _inputParams->IsValid());
			Assert::IsFalse( _inputParams->Validate());
			Assert::IsFalse( _inputParams->IsAnalysisSet());
			Assert::IsTrue( _inputParams->AddParam(new ProcParamDouble(0, "test", IPluginICProcStepsParam::input, 1.0)));	
			Assert::IsTrue( _inputParams->Validate());
			Assert::IsFalse( _inputParams->IsAnalysisSet());

			Assert::IsTrue( _outputParams->AddParam(new ProcParamDouble(0, IPluginICProcStepsParamAttribOutputNameScore, IPluginICProcStepsParam::input, 1.0)));	//result is OK if score > 1.0, else NOK
			Assert::IsFalse( _outputParams->Validate());		//no result param

			Assert::IsTrue( _outputParams->AddParam(new ProcParamDouble(1, IPluginICProcStepsParamAttribOutputNameResult, IPluginICProcStepsParam::input,  1.0)));	//result is OK if score > 1.0, else NOK
			Assert::IsFalse( _outputParams->IsValid());			//validate needs to be called first
			Assert::IsTrue( _outputParams->Validate());		
			Assert::IsTrue(_outputParams->IsValid());	
			Assert::AreEqual(2,  _outputParams->GetParamCount());
		
			Assert::IsTrue( _outputParams->IsAnalysisSet());

			Assert::IsTrue( _inputParams->ClearParams());
			Assert::AreEqual(ProcParams::NotFound,  _inputParams->GetParamCount());

			Assert::IsTrue( _outputParams->ClearParams());
			Assert::AreEqual( ProcParams::NotFound,  _outputParams->GetParamCount());
		}

		TEST_METHOD(OutputParamsIsValidTest)
		{
			Assert::AreEqual( ProcParams::NotFound,  _outputParams->GetParamCount());

			Assert::IsFalse( _outputParams->IsValid());
			Assert::IsFalse(_outputParams->IsAnalysisSet());
			Assert::AreEqual(  ProcParamsOutputs::ScoreInvalid, _outputParams->GetScore());
			Assert::AreEqual(  ProcParamsOutputs::ResultInvalid, _outputParams->GetResultCode());

			Assert::IsTrue( _outputParams->AddParam(new ProcParamInt(0, IPluginICProcStepsParamAttribOutputNameResult, IPluginICProcStepsParam::output, ProcParamsOutputs::ResultNotSet)));
			Assert::IsTrue(_outputParams->Validate());
			Assert::AreEqual(  1,  _outputParams->GetParamCount());

			Assert::IsTrue( _outputParams->AddParam(new ProcParamDouble(1, IPluginICProcStepsParamAttribOutputNameScore, IPluginICProcStepsParam::output, 1.0)));	//result is OK if score > 1.0, else NOK
			Assert::IsTrue(_outputParams->Validate());
			Assert::AreEqual(  2,  _outputParams->GetParamCount());
			Assert::IsTrue( _outputParams->IsAnalysisSet());

			Assert::IsTrue( _outputParams->AddParam(new ProcParamString(2, "resultmsg", IPluginICProcStepsParam::output, "done")));
			Assert::IsTrue( _outputParams->Validate());
			Assert::AreEqual( 3,  _outputParams->GetParamCount());
		
			Assert::IsTrue( _outputParams->Validate());
			Assert::IsTrue( _outputParams->IsValid());
			Assert::IsTrue( _outputParams->IsAnalysisSet());

			Assert::IsTrue( _outputParams->ClearParams());
			Assert::AreEqual(  ProcParams::NotFound,  _outputParams->GetParamCount());
		}

		TEST_METHOD(OutputParamsSetValueResultScoreTest)
		{
			Assert::AreEqual(  ProcParams::NotFound,  _outputParams->GetParamCount());

			Assert::IsTrue( _outputParams->AddParam(new ProcParamInt(0, IPluginICProcStepsParamAttribOutputNameResult, IPluginICProcStepsParam::output, ProcParamsOutputs::ResultNotSet)));
			Assert::IsTrue( _outputParams->Validate());
			Assert::AreEqual(  1,  _outputParams->GetParamCount());
			Assert::IsTrue( _outputParams->AddParam(new ProcParamDouble(1, IPluginICProcStepsParamAttribOutputNameScore, IPluginICProcStepsParam::output,  1.0)));	//result is OK if score > 1.0, else NOK
			Assert::IsTrue(_outputParams->Validate());
			Assert::AreEqual(  2,  _outputParams->GetParamCount());
			Assert::IsTrue( _outputParams->AddParam(new ProcParamString(2, "resultmsg", IPluginICProcStepsParam::output, "done")));
			Assert::IsTrue(_outputParams->Validate());
			Assert::AreEqual(  3,  _outputParams->GetParamCount());
			Assert::IsTrue( _outputParams->IsAnalysisSet());

											//before setting Score (or Result)
			ProcParamString *resultmsg = dynamic_cast<ProcParamString *>(_outputParams->GetParam("resultmsg"));	//need to be able to get output param before setting result so as to get PassScore
			Assert::IsNotNull(resultmsg);
			Assert::AreEqual(  1.0, _outputParams->GetScore());		//PassScore
			Assert::AreEqual(  ProcParamsOutputs::ResultNotSet, _outputParams->GetResultCode());
			Assert::IsFalse(_outputParams->IsResultOK());
			Assert::AreEqual(  "done", resultmsg->GetValue() );
			Assert::IsTrue(_outputParams->SetParamValue("resultmsg", "ok"));
			Assert::AreEqual(  "ok", resultmsg->GetValue() );

			Assert::IsFalse(_outputParams->SetScore(2.0));		//cannot set score until set result
											//set result
			Assert::IsFalse( _outputParams->SetResultCode(1));	//1 is reserved for ProcParamsOutputs::ResultNotSet
			Assert::IsTrue(_outputParams->SetResultCode(10));
			Assert::IsFalse(_outputParams->SetScore(2.0));		//cannot set score if result not ResultOK

			Assert::IsTrue(_outputParams->SetResultCode(ProcParamsOutputs::ResultOK));
			Assert::AreEqual(  ProcParamsOutputs::ResultOK, _outputParams->GetResultCode());
			Assert::IsTrue(_outputParams->IsResultOK());
											//set score > PassScore 
			Assert::IsTrue(_outputParams->SetScore(2.0));		//PassScore now 2.0
			Assert::AreEqual( 2.0, _outputParams->GetScore());
			Assert::AreEqual( ProcParamsOutputs::ResultOK, _outputParams->GetResultCode());
			Assert::IsTrue( _outputParams->IsResultOK());
											//set score == PassScore 
			Assert::IsTrue(_outputParams->SetScore(2.0));		//PassScore now 2.0
			Assert::AreEqual(  2.0, _outputParams->GetScore());
			Assert::AreEqual(  ProcParamsOutputs::ResultOK, _outputParams->GetResultCode());
			Assert::IsTrue( _outputParams->IsResultOK());
											//set score < PassScore 
			Assert::IsTrue(_outputParams->SetScore(1.9));		//PassScore now 1.9
			Assert::AreEqual( 1.9, _outputParams->GetScore());
			Assert::AreEqual( ProcParamsOutputs::ResultScoreFail, _outputParams->GetResultCode());
			Assert::IsFalse(_outputParams->IsResultOK());
		}

	};
}